import pygame, time, random

_display = pygame.display
COLOR_BLACK = pygame.Color(0, 0, 0)
COLOR_WHITE = pygame.Color(255,255,255)
COLOR_WATHET = pygame.Color(0, 255, 255)
version = 'TvT'


class MainGame():  # 主逻辑类
    # 游戏主窗口
    window = None
    SCREEN_WIDTH = 900
    SCREEN_HEIGHT = 600
    # 背景图片
    background = pygame.image.load('image/background_shamo.jpg')
    # 死亡图片
    deathimage1 = pygame.image.load('image/deathimage1.jpeg')
    deathimage2 = pygame.image.load('image/deathimage2.jpeg')
    deathimage3 = pygame.image.load('image/deathimage3.jpeg')
    # 创建我方坦克
    TANK_P1 = None
    # 存储所有敌方tank
    EnemyTank_list = []
    # 要创建敌方坦克的数量
    EnemyTank_count = random.randint(3,10)
    # 创建我方坦克HP
    HP = 5
    # 存储我方子弹列表
    Bullet_list = []
    # 存储敌方子弹列表
    eBullet_list = []
    # 存储爆炸效果列表
    Exploe_list = []
    # 存储障碍列表
    Obstacle_list = []
    # 存储位置字典
    position = {}

    def __init__(self):
        pass

    # 开始游戏
    def startGame(self):
        _display.init()
        # 创建窗口加载窗口(借鉴官方文档)
        MainGame.window = _display.set_mode([MainGame.SCREEN_WIDTH, MainGame.SCREEN_HEIGHT])
        self.creatMyTank()
        # ? 创建敌方坦克
        self.creatEnemyTank()
        # 创建障碍
        self.creatObstacle()
        # 设置游戏标题
        _display.set_caption(version)


        # 让窗口持续刷新
        while True:
            time.sleep(0.03)
            # 给窗口完成一个填充色
            # MainGame.window.fill(COLOR_BLACK)
            # 给窗口能完成一个背景
            MainGame.window.blit(MainGame.background, (0, 0))
            # 持续调用事件获取
            self.getEvent()
            if MainGame.TANK_P1 and MainGame.TANK_P1.live:
                # 将我方坦克加入窗口中
                MainGame.TANK_P1.displayTank()
            else:
                del MainGame.TANK_P1
                # del MainGame.position[MyTank]     'KeyError: <class '__main__.MyTank'>' 目前不会解决——2022.4.20 18：38
                MainGame.TANK_P1 = None
            # 将障碍加入窗口
            self.biltObstacle()
            # 循环展示敌方坦克
            self.blitEnemyTank()
            # 将绘制文字得到的小画布，粘贴至窗口中
            MainGame.window.blit(self.getTextSurface('剩余敌方数:%d' % len(MainGame.EnemyTank_list)), (5, 5))
            MainGame.window.blit(self.getTextSurface('H P：%d' % MainGame.HP), (10, 30))
            if not MainGame.TANK_P1 or MainGame.TANK_P1.stop:
                pass
            # 根据坦克开关状态 调用坦克的移动方法
            else:
                MainGame.TANK_P1.move()
                # 调用碰撞障碍的方法
                MainGame.TANK_P1.hitObstacle()
                MainGame.TANK_P1.hitEnemyTank()
            # 调用渲染子弹列表的一个方法
            self.blitBullet()
            # 调用渲染敌方子弹列表的一个方法
            self.blitEnemyBullet()
            # 调用展示爆炸效果的方法
            self.displayExplodes()
            if MainGame.HP <= 0:
                MainGame.window.fill(COLOR_WHITE)
                MainGame.window.blit(MainGame.deathimage1,(0,0))
                MainGame.window.blit(MainGame.deathimage2,(500,0))
                MainGame.window.blit(MainGame.deathimage3,(250,200))
            # 窗口的刷新
            _display.update()

    # 创建我方坦克
    def creatMyTank(self):
        flag = True
        # 创建我方坦克
        if len(MainGame.position) == 0:
            x = random.randint(0, MainGame.SCREEN_WIDTH // 30 - 1)
            y = random.randint(0, MainGame.SCREEN_HEIGHT // 30 - 1)
            MainGame.TANK_P1 = MyTank(x * 30, y * 30)
            MainGame.position.update({MyTank: [x * 30, y * 30, 30, 30]})
        else:
            while flag:
                c = 0
                x = random.randint(0, MainGame.SCREEN_WIDTH // 30 - 1)
                y = random.randint(0, MainGame.SCREEN_HEIGHT // 30 - 1)
                for position in MainGame.position:
                    l, t, w, h = MainGame.position[position][0], MainGame.position[position][1], \
                                 MainGame.position[position][2], MainGame.position[position][3]
                    r1 = pygame.Rect(x * 30, y * 30, 30, 30)
                    r2 = pygame.Rect(l, t, w, h)
                    if r1.colliderect(r2):
                        continue
                    else:
                        c += 1
                    if c == len(MainGame.position):
                        flag = False
                        MainGame.TANK_P1 = MyTank(x * 30, y * 30)
                        MainGame.position.update({MyTank: [x * 30, y * 30, 30, 30]})
                        break

    # 创建敌方坦克
    def creatEnemyTank(self):
        flag = True
        for i in range(MainGame.EnemyTank_count):
            while flag:
                c = 0
                # 每次都随机生成left,top,speed的值
                left = random.randint(0, MainGame.SCREEN_WIDTH // 30 - 1)
                top = random.randint(0, MainGame.SCREEN_HEIGHT // 30 - 1)
                speed = random.randint(2, 5)
                for position in MainGame.position:
                    l, t, w, h = MainGame.position[position][0], MainGame.position[position][1], \
                                 MainGame.position[position][2], MainGame.position[position][3]
                    r1 = pygame.Rect(left * 30, top * 30, 30, 30)
                    r2 = pygame.Rect(l, t, w, h)
                    if r1.colliderect(r2):
                        continue
                    else:
                        c += 1
                    if c == len(MainGame.position):
                        flag = False
                        eTank = EnemyTank(left * 30, top * 30, speed)
                        MainGame.EnemyTank_list.append(eTank)
                        MainGame.position.update({eTank: [left * 30, top * 30, 30, 30]})
                        break
            flag = True

    # 将敌方坦克加入窗口中
    def blitEnemyTank(self):
        for eTank in MainGame.EnemyTank_list:
            if eTank.live:
                eTank.displayTank()
                # 坦克的移动方法
                eTank.randMove()
                # 调用敌方坦克与障碍的碰撞方法
                eTank.hitObstacle()
                # 敌方坦克是否碰撞其他坦克
                eTank.hitTank()
                # 调用敌方坦克的射击方法
                eBullet = eTank.shot()
                # 如果子弹为None，不加入列表
                if eBullet:
                    # 将子弹存储到敌方子弹列表
                    MainGame.eBullet_list.append(eBullet)
            else:

                MainGame.EnemyTank_list.remove(eTank)
                del MainGame.position[eTank]

    # 将我方子弹加入到窗口中
    def blitBullet(self):
        for bullet in MainGame.Bullet_list:
            # 如果子弹活着，则发射子弹；否则，将子弹从列表中移出
            if bullet.live:
                bullet.dispalyBullet()
                # 让子弹移动
                bullet.bulletmove()
                # 调用我方子弹与敌方坦克碰撞方法
                bullet.hitEnemyTank()
                # 调用判断我方子弹是否碰撞障碍的方法
                bullet.hitObstacle()
            else:

                MainGame.Bullet_list.remove(bullet)

    # 将敌方子弹加入窗口中
    def blitEnemyBullet(self):
        for eBullet in MainGame.eBullet_list:
            # 如果子弹活着，则发射子弹；否则，将子弹从列表中移出
            if eBullet.live:
                eBullet.dispalyBullet()
                # 让子弹移动
                eBullet.bulletmove()
                # 调用是否碰撞到障碍
                eBullet.hitObstacle()
                if MainGame.TANK_P1 and MainGame.TANK_P1.live:
                    eBullet.hitMyTank()
            else:
                MainGame.eBullet_list.remove(eBullet)

    # 展示爆炸效果列表
    def displayExplodes(self):
        for explode in MainGame.Exploe_list:
            if explode.live:
                explode.displayExplode()
            else:
                MainGame.Exploe_list.remove(explode)

    # 创建障碍的方法
    def creatObstacle(self):
        flag = True
        for i in range(
                int((MainGame.SCREEN_HEIGHT // 100) * (MainGame.SCREEN_WIDTH / 100) - MainGame.EnemyTank_count * 2)):
            while flag:
                c = 0
                left = random.randint(0, MainGame.SCREEN_WIDTH // 60)
                top = random.randint(0, MainGame.SCREEN_HEIGHT // 40)
                for position in MainGame.position:
                    l, t, w, h = MainGame.position[position][0], MainGame.position[position][1], \
                                 MainGame.position[position][2], MainGame.position[position][3]
                    r1 = pygame.Rect(left * 60, top * 40, 60, 40)
                    r2 = pygame.Rect(l, t, w, h)
                    if r1.colliderect(r2):
                        continue
                    else:
                        c += 1
                    if c == len(MainGame.position):
                        flag = False
                        obstacle = Obstacle(left * 60, top * 40)
                        MainGame.Obstacle_list.append(obstacle)
                        MainGame.position.update({obstacle: [left * 60, top * 40, 60, 40]})
                        break
            flag = True

    # 将障碍加入窗口中
    def biltObstacle(self):
        for obstacle in MainGame.Obstacle_list:
            if obstacle.live:
                obstacle.displayObstacle()
            else:
                MainGame.Obstacle_list.remove(obstacle)
                del MainGame.position[obstacle]

    # 获取程序期间所有事件(鼠标事件，键盘事件)
    def getEvent(self):
        # 1.获取所有事件
        eventlist = pygame.event.get()
        # 2.对事件进行判断处理(1.点击关闭按钮 2. 按下键盘的某个按键)
        for event in eventlist:
            # 判断event.type 是否为QUIT，如果是退出的话，直接调用程序结束方法
            if event.type == pygame.QUIT:
                self.endGame()

            # 判断event.type 是否为按键按下，如果是的话，继续判断按键为哪个键，来进行对应出来
            if event.type == pygame.KEYDOWN:
                if MainGame.HP <= 0:
                    if event.key == pygame.K_SPACE:
                        # 游戏主窗口
                        MainGame.window = None
                        MainGame.SCREEN_WIDTH = 900
                        MainGame.SCREEN_HEIGHT = 600
                        MainGame.background = pygame.image.load('image/background_shamo.jpg')
                        # 创建我方坦克
                        MainGame.TANK_P1 = None
                        # 存储所有敌方tank
                        MainGame.EnemyTank_list = []
                        # 要创建敌方坦克的数量
                        MainGame.EnemyTank_count = random.randint(3, 10)
                        # 创建我方坦克HP
                        MainGame.HP = 5
                        # 存储我方子弹列表
                        MainGame.Bullet_list = []
                        # 存储敌方子弹列表
                        MainGame.eBullet_list = []
                        # 存储爆炸效果列表
                        MainGame.Exploe_list = []
                        # 存储障碍列表
                        MainGame.Obstacle_list = []
                        # 存储位置字典
                        MainGame.position = {}
                        self.startGame()
                else:
                    # 点击Esc键让我方坦克重生
                    if event.key == pygame.K_ESCAPE and not MainGame.TANK_P1:
                        # 调用创建我方坦克的方法
                        self.creatMyTank()
                    if MainGame.TANK_P1 and MainGame.TANK_P1.live:
                        # 具体是哪一个按键的处理
                        if event.key == pygame.K_LEFT:
                            print('向左调头、移动')
                            # 修改坦克方向
                            MainGame.TANK_P1.direction = 'L'
                            MainGame.TANK_P1.stop = False
                            # 完成移动操作(调用坦克移动方法)
                            # MainGame.TANK_P1.move()
                        elif event.key == pygame.K_RIGHT:
                            print('向右调头、移动')
                            # 修改坦克方向
                            MainGame.TANK_P1.direction = 'R'
                            MainGame.TANK_P1.stop = False
                            # 完成移动操作(调用坦克移动方法)
                            # MainGame.TANK_P1.move()
                        elif event.key == pygame.K_UP:
                            print('向上调头、移动')
                            # 修改坦克方向
                            MainGame.TANK_P1.direction = 'U'
                            MainGame.TANK_P1.stop = False
                            # 完成移动操作(调用坦克移动方法)
                            # MainGame.TANK_P1.move()
                        elif event.key == pygame.K_DOWN:
                            print('向下调头、移动')
                            # 修改坦克方向
                            MainGame.TANK_P1.direction = 'D'
                            MainGame.TANK_P1.stop = False
                            # 完成移动操作(调用坦克移动方法)
                            # MainGame.TANK_P1.move()
                        elif event.key == pygame.K_SPACE:
                            print('冲呀!!')
                            if MainGame.TANK_P1 and MainGame.TANK_P1.live:
                                if len(MainGame.Bullet_list) < len(MainGame.EnemyTank_list):
                                    # 产生一颗子弹
                                    m = Bullet(MainGame.TANK_P1)
                                    # 将子弹加入子弹列表
                                    MainGame.Bullet_list.append(m)
                                    music = Music('music/fashe.mp3')
                                    music.play()
                                else:
                                    print('皇军弹尽粮绝了~_~!')
                                print('当前屏幕中的子弹数为%d' % len(MainGame.Bullet_list))
            if event.type == pygame.KEYUP:
                if MainGame.TANK_P1 and MainGame.TANK_P1.live:
                    if event.key != pygame.K_LEFT and event.key != pygame.K_RIGHT and event.key != pygame.K_UP and event.key != pygame.K_DOWN:
                        continue
                    # 松开的按键为方向键 修改坦克移动状态
                    MainGame.TANK_P1.stop = True

    # 左上角文字绘制的功能
    def getTextSurface(self, text):
        # 初始化字体模块
        pygame.font.init()

        """
        查看系统支持的所有字体
             fontlist = pygame.font.get_fonts()
             print(fontlist)
        """

        # 选中一个合适的字体
        font = pygame.font.SysFont('kaiti', 21)
        # 使用对应的字体完成相关内容的绘制
        textSurface = font.render(text, True, COLOR_WATHET)
        return textSurface

    # 结束游戏
    def endGame(self):
        print('谢谢使用')
        # 结束python解释器
        exit()


class BaseItem(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)


class Tank(BaseItem):  # 坦克类
    def __init__(self, left, top):
        self.images = {
            'U': pygame.image.load('image/P1‘U’.png'),
            'D': pygame.image.load('image/P1‘D’.png'),
            'L': pygame.image.load('image/P1‘L’.png'),
            'R': pygame.image.load('image/P1‘R’.png')
        }
        self.direction = 'U'
        self.image = self.images[self.direction]
        # 坦克所在的区域   Rect->
        self.rect = self.image.get_rect()
        # 指定坦克初始化位置，分别据x，y轴的位置
        self.rect.left = left
        self.rect.top = top
        # 新增速度属性
        self.speed = 5
        # 新增坦克移动开关属性
        self.stop = True
        # 新增属性 live 用来记录坦克是否活着
        self.live = True
        # 新增属性 用来记录坦克移动之前的坐标(用于坐标还原)
        self.oldLeft = self.rect.left
        self.oldTop = self.rect.top

    # 坦克的移动方法
    def move(self):
        # 先记录移动之前的坐标
        self.oldLeft = self.rect.left
        self.oldTop = self.rect.top
        if self.direction == 'L':
            if self.rect.left > 0:
                self.rect.left -= self.speed
        elif self.direction == 'R':
            if self.rect.left + self.rect.height < MainGame.SCREEN_WIDTH:
                self.rect.left += self.speed
        elif self.direction == 'U':
            if self.rect.top > 0:
                self.rect.top -= self.speed
        elif self.direction == 'D':
            if self.rect.top + self.rect.height < MainGame.SCREEN_HEIGHT:
                self.rect.top += self.speed

    # 还原方法
    def stay(self):
        self.rect.left = self.oldLeft
        self.rect.top = self.oldTop

    # 新增碰撞障碍的方法
    def hitObstacle(self):
        for obstacle in MainGame.Obstacle_list:
            if pygame.sprite.collide_rect(obstacle, self):
                self.stay()

    # 坦克的射击方法
    def shot(self):
        return Bullet(self)

    # 展示坦克(将坦克这个surface绘制到窗口中 blit())
    def displayTank(self):
        # 1.重新设置坦克的图片
        self.image = self.images[self.direction]
        # 2.将坦克加入到窗口
        MainGame.window.blit(self.image, self.rect)


class MyTank(Tank):  # 我方坦克类
    def __init__(self, left, top):
        super(MyTank, self).__init__(left, top)

    # 新增主动碰撞敌方坦克的方法
    def hitEnemyTank(self):
        for eTank in MainGame.EnemyTank_list:
            if pygame.sprite.collide_rect(eTank, self):
                self.stay()


class EnemyTank(Tank):  # 敌方坦克类
    def __init__(self, left, top, speed):
        super(EnemyTank, self).__init__(left, top)
        self.images = {
            'U': pygame.image.load('image/P2‘U’.png'),
            'D': pygame.image.load('image/P2‘D’.png'),
            'L': pygame.image.load('image/P2‘L’.png'),
            'R': pygame.image.load('image/P2‘R’.png')
        }
        self.direction = self.randDirection()
        self.image = self.images[self.direction]
        # 坦克所在的区域   Rect->
        self.rect = self.image.get_rect()
        # 指定坦克初始化位置，分别据x，y轴的位置
        self.rect.left = left
        self.rect.top = top
        # 新增速度属性
        self.speed = speed
        # 新增坦克移动开关属性
        self.stop = True
        # 新增步数属性，用来控制敌方坦克的随机移动
        self.step = 25

    def randDirection(self):
        num = random.randint(1, 4)
        if num == 1:
            return 'U'
        elif num == 2:
            return 'D'
        elif num == 3:
            return 'L'
        elif num == 4:
            return 'R'

    # def displayEnemyTank(self):
    #     super().displayTank()

    # 随机移动
    def randMove(self):
        if self.step <= 0:  # (步数为0)
            self.direction = self.randDirection()  # (更改方向)
            self.step = 35  # (步数复位)
        else:
            self.move()
            self.step -= 1  # (步数-1)

    def shot(self):
        num = random.randint(1, 1000)
        if num <= 30:
            return Bullet(self)

    def hitTank(self):
        if MainGame.TANK_P1:
            if pygame.sprite.collide_rect(self, MainGame.TANK_P1):
                self.stay()


class Bullet(BaseItem):  # 子弹类
    def __init__(self, tank):
        # 图片
        self.images = {
            'U': pygame.image.load('image/Bullet‘U’.png'),
            'D': pygame.image.load('image/Bullet‘D’.png'),
            'L': pygame.image.load('image/Bullet‘L’.png'),
            'R': pygame.image.load('image/Bullet‘R’.png')
        }
        # 方向(坦克方向)
        self.direction = tank.direction
        self.image = self.images[self.direction]
        # 位置
        self.rect = self.image.get_rect()
        if self.direction == 'U':
            self.rect.left = tank.rect.left + tank.rect.width / 2 - self.rect.width / 2
            self.rect.top = tank.rect.top - self.rect.height
        elif self.direction == 'D':
            self.rect.left = tank.rect.left + tank.rect.width / 2 - self.rect.width / 2
            self.rect.top = tank.rect.top + tank.rect.height
        elif self.direction == 'L':
            self.rect.left = tank.rect.left - self.rect.width
            self.rect.top = tank.rect.top + tank.rect.width / 2 - self.rect.width / 2
        elif self.direction == 'R':
            self.rect.left = tank.rect.left + tank.rect.width
            self.rect.top = tank.rect.top + tank.rect.width / 2 - self.rect.width / 2
        # 速度
        self.speed = 10
        # 用来记录子弹是否碰撞
        self.live = True

    # 子弹的移动方法
    def bulletmove(self):
        if self.direction == 'U':
            if self.rect.top > 0:
                self.rect.top -= self.speed
            else:
                # 修改状态值
                self.live = False
        elif self.direction == 'D':
            if self.rect.top <= MainGame.SCREEN_HEIGHT - self.rect.height:
                self.rect.top += self.speed
            else:
                # 修改状态值
                self.live = False
        elif self.direction == 'R':
            if self.rect.left <= MainGame.SCREEN_WIDTH - self.rect.width:
                self.rect.left += self.speed
            else:
                # 修改状态值
                self.live = False
        elif self.direction == 'L':
            if self.rect.left > 0:
                self.rect.left -= self.speed
            else:
                # 修改状态值
                self.live = False

    # 子弹的展示方法
    def dispalyBullet(self):
        MainGame.window.blit(self.image, self.rect)

    # 新增我方子弹碰撞敌方坦克的方法
    def hitEnemyTank(self):
        for eTank in MainGame.EnemyTank_list:
            if pygame.sprite.collide_rect(eTank, self):
                # 产生爆炸效果
                explode = Explode(eTank)
                # 将爆炸效果加入到爆炸效果列表中
                MainGame.Exploe_list.append(explode)
                self.live = False
                eTank.live = False

    # 新增敌方子弹与我方坦克的碰撞的方法
    def hitMyTank(self):
        if pygame.sprite.collide_rect(self, MainGame.TANK_P1):
            # 产生爆炸效果，并加入到爆炸效果列表中
            explode = Explode(MainGame.TANK_P1)
            MainGame.Exploe_list.append(explode)
            MainGame.HP -= 1
            # 修改子弹状态
            self.live = False
            # 修改我方坦克状态
            MainGame.TANK_P1.live = False

    # 新增子弹与障碍的碰撞的方法
    def hitObstacle(self):
        for obstacle in MainGame.Obstacle_list:
            if pygame.sprite.collide_rect(obstacle, self):
                # 修改子弹的live属性
                self.live = False
                obstacle.hp -= 1
                if obstacle.hp <= 0:
                    obstacle.live = False


class Explode():  # 爆炸效果类
    def __init__(self, tank):
        self.rect = tank.rect
        self.step = 0
        self.images = [
            pygame.image.load('image/Boom‘1’.png'),
            pygame.image.load('image/Boom‘2’.png'),
            pygame.image.load('image/Boom‘3’.png'),
            pygame.image.load('image/Boom‘4’.png'),
            pygame.image.load('image/Boom‘5’.png'),
            pygame.image.load('image/Boom‘6’.png'),
            pygame.image.load('image/Boom‘7’.png'),
            pygame.image.load('image/Boom‘8’.png'),
            pygame.image.load('image/Boom‘9’.png'),
            pygame.image.load('image/Boom‘10’.png'),
            pygame.image.load('image/Boom‘11’.png'),
            pygame.image.load('image/Boom‘12’.png'),
            pygame.image.load('image/Boom‘13’.png'),
            pygame.image.load('image/Boom‘14’.png'),
            pygame.image.load('image/Boom‘15’.png'),
            pygame.image.load('image/Boom‘16’.png'),
            pygame.image.load('image/Boom‘17’.png')
        ]
        self.image = self.images[self.step]
        self.live = True

    # 展示爆炸效果
    def displayExplode(self):
        if self.step < len(self.images):
            MainGame.window.blit(self.image, self.rect)
            self.image = self.images[self.step]
            self.step += 1
        else:
            self.live = False
            self.step = 0


class Obstacle():  # 障碍类

    def __init__(self, left, top):
        self.images = [
            pygame.image.load('image/Stone1.png'),
            pygame.image.load('image/Stone2.png'),
            pygame.image.load('image/Stone3.png')
        ]
        num = random.randint(0, 2)
        self.image = self.images[num]
        self.rect = self.image.get_rect()
        self.rect.left = left
        self.rect.top = top
        # 用来判断墙壁是否在窗口中展示
        self.live = True
        # 用来记录障碍的生命值
        self.hp = 7

    # 展示障碍
    def displayObstacle(self):
        MainGame.window.blit(self.image, self.rect)


# 登场，发射子弹，爆炸等音效
class Music():  # 音乐类
    def __init__(self, fileName):
        self.filename = fileName
        # 先初始化混响器
        pygame.mixer.init()
        pygame.mixer.music.load(self.filename)

    # 开始播放音乐
    def playzhutiqu(self):
        pygame.mixer.music.play(-1)

    def play(self):
        pygame.mixer.music.play()


if __name__ == '__main__':
    MainGame().startGame()
